package com.deer.wms.instock.web;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.deer.wms.ASN.manage.constant.AsnManageConstant;
import com.deer.wms.ASN.manage.model.in.AcceptRecord;
import com.deer.wms.ASN.manage.service.AcceptRecordService;
import com.deer.wms.base.system.constant.BaseSystemConstant;
import com.deer.wms.base.system.model.Cell.CellInfo;
import com.deer.wms.base.system.model.Cell.CellInfoDto;
import com.deer.wms.base.system.service.CellInfoService;
import com.deer.wms.base.system.service.ItemInfoService;
import com.deer.wms.busine.tactic.model.Upper.UpperTacticDetailDto;
import com.deer.wms.busine.tactic.service.UpperTacticService;
import com.deer.wms.instock.constant.InStockConstant;
import com.deer.wms.instock.model.Allot.TransferBillCriteria;
import com.deer.wms.instock.model.transfer.*;
import com.deer.wms.instock.service.TransferBillService;
import com.deer.wms.intercept.annotation.User;
import com.deer.wms.intercept.common.data.CurrentUser;
import com.deer.wms.inventory.constant.InventoryConstant;
import com.deer.wms.inventory.model.Inventory.Inventory;
import com.deer.wms.inventory.model.Inventory.InventoryCriteria;
import com.deer.wms.inventory.model.Inventory.InventoryDto;
import com.deer.wms.inventory.service.InventoryService;
import com.deer.wms.project.root.core.result.CommonCode;
import com.deer.wms.project.root.core.result.Result;
import com.deer.wms.project.root.core.result.ResultGenerator;
import com.deer.wms.project.root.exception.ServiceException;
import com.deer.wms.ware.task.service.PickTaskService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * @author : wei
 * @since : 2022-01-08 20:37:44
 **/
@Api(description = "转移单API接口")
@RestController
@RequestMapping("/transfer")
public class TransferBillController {

    @Autowired
    private TransferBillService transferBillService;
    @Autowired
    private AcceptRecordService acceptRecordService;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private PickTaskService pickTaskService;
    @Autowired
    private CellInfoService cellInfoService;
    @Autowired
    private UpperTacticService upperTacticService;
    @Autowired
    private ItemInfoService itemInfoService;

    @ApiOperation(value = "生成装箱单", notes = "PDA")
    @PostMapping("create/pack/box")
    public Result createPackBoxForPda(@RequestBody PackBoxData packBoxData, @ApiIgnore @User CurrentUser currentUser) {

        //Step1.解析前台传来的数据
        String acceptRecordCode = packBoxData.getAcceptRecordCode();
        AcceptRecord acceptRecord = acceptRecordService.getOneByField("accept_record_code", acceptRecordCode);
        List<PackBox> list = packBoxData.getList();
        //Step2.准备数据
        List<TransferBill> transferBills = new ArrayList<>();
        for (PackBox packBox : list) {
            TransferBill transferBill = new TransferBill();
            //仓库
            transferBill.setWareId(acceptRecord.getWareId());
            //转移单类型
            transferBill.setBillType(InStockConstant.TRANS_TYPE_PACK_BOX);
            //来源库位 收货区库位   无目标库位
            transferBill.setFromCellCode(acceptRecord.getCellCode());
            transferBill.setToCellCode(acceptRecord.getCellCode());
            //无来源容器  目标容器
            transferBill.setToBoxCode(packBox.getBoxCode());
            transferBill.setItemCode(packBox.getItemCode());
            transferBill.setBatchName(packBox.getBatchName());
            transferBill.setPackDetailId(acceptRecord.getPackDetailId());
            transferBill.setQty(new BigDecimal(packBox.getQty()));
            //标记冻结解冻标识
            if (AsnManageConstant.ACCEPT_QC_STATE_TODO.equals(acceptRecord.getQcState())) {
                //说明是待检的物料
                transferBill.setFreezeFlag(AsnManageConstant.ACCEPT_QC_STATE_TODO);
            }
            //确认人
            transferBill.setConfirmUserId(currentUser.getUserId());
            transferBill.setConfirmUserName(currentUser.getUserName());
            transferBills.add(transferBill);
        }
        //Step3.保存
        transferBillService.saveAndConfirmTransferBill(transferBills);

        return ResultGenerator.genSuccessResult();
    }

    @ApiOperation(value = "上架", notes = "PDA")
    @PostMapping("create/upper")
    public Result createUpperForPda(@RequestBody UpperData upperData, @ApiIgnore @User CurrentUser currentUser) {

        //Step1.解析前台传来的数据
        String wareId = upperData.getWareId();
        List<Upper> upperList = upperData.getUpperList();

        //Step2.准备数据
        List<TransferBill> transferBills = new ArrayList<>();
        for (Upper upper : upperList) {
            TransferBill transferBill = new TransferBill();
            //仓库
            transferBill.setWareId(Integer.parseInt(wareId));
            //转移单类型
            transferBill.setBillType(InStockConstant.TRANS_TYPE_UPPER);
            //来源库位 收货区库位
            Inventory boxIvt = inventoryService.getOneByField("box_code", upper.getBoxCode());
            if (ObjectUtil.isNull(boxIvt)) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "根据容器号：" + upper.getBoxCode() + "未找到对应的库存");
            }
            //FIXME: 这里写死，冻结的物料不能上架
            if (InventoryConstant.TRANSACT_STATE_UNNORMAL.equals(boxIvt.getState())) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "容器内物料未质检，禁止上架!");
            }
            transferBill.setFromCellCode(boxIvt.getCellCode());
            //目标库位
            transferBill.setToCellCode(upper.getCellCode());
            //来源容器
            transferBill.setFromBoxCode(upper.getBoxCode());
            transferBill.setItemCode(boxIvt.getItemCode());
            transferBill.setBatchName(boxIvt.getBatchName());
            transferBill.setPackDetailId(boxIvt.getPackDetailId());
            transferBill.setQty(new BigDecimal(boxIvt.getQuantity()));
            //标记冻结解冻标识
            if (boxIvt.getFreezeQuantity() > 0) {
                //说明是待检的物料
                transferBill.setFreezeFlag(AsnManageConstant.ACCEPT_QC_STATE_TODO);
            }
            //确认人
            transferBill.setConfirmUserId(currentUser.getUserId());
            transferBill.setConfirmUserName(currentUser.getUserName());
            transferBills.add(transferBill);
        }
        //Step3.保存
        transferBillService.saveAndConfirmTransferBill(transferBills);
        String billNo = upperList.get(0).getBillNo();
        acceptRecordService.billToErpNew(billNo, 2);
        return ResultGenerator.genSuccessResult();
    }

    @ApiOperation(value = "转移", notes = "PDA")
    @PostMapping("create/transfer")
    public Result createTransferForPda(@RequestBody Upper upper, @ApiIgnore @User CurrentUser currentUser) {
        //Step1.准备数据
        TransferBill transferBill = new TransferBill();
        //转移单类型
        transferBill.setBillType(InStockConstant.TRANS_TYPE_MOVE);
        //来源容器库存
        Inventory boxIvt = inventoryService.getOneByField("box_code", upper.getBoxCode());
        if (ObjectUtil.isNull(boxIvt)) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "根据容器号：" + upper.getBoxCode() + "未找到对应的库存");
        }
        //冻结的物料不能转移
        if (InventoryConstant.TRANSACT_STATE_UNNORMAL.equals(boxIvt.getState())) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "容器内物料未质检，禁止上架!");
        }
        //判断目标库位是否合法
        CellInfo cellInfo = cellInfoService.getOneByField("cell_code", upper.getCellCode());
        if (ObjectUtil.isNull(cellInfo)) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "未查询到目标库位:[" + upper.getCellCode() + "]!");
        }
        if (ObjectUtil.notEqual(BaseSystemConstant.CELL_USE_TYPE_STORE, cellInfo.getCellUseType())) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "库位:[" + upper.getCellCode() + "]不为存储库位，不允许转移!");
        }

        //仓库
        transferBill.setWareId(boxIvt.getWareId());
        //来源库位
        transferBill.setFromCellCode(boxIvt.getCellCode());
        //目标库位
        transferBill.setToCellCode(upper.getCellCode());
        //来源容器
        transferBill.setFromBoxCode(upper.getBoxCode());
        transferBill.setItemCode(boxIvt.getItemCode());
        transferBill.setBatchName(boxIvt.getBatchName());
        transferBill.setPackDetailId(boxIvt.getPackDetailId());
        transferBill.setQty(new BigDecimal(boxIvt.getQuantity()));
        //确认人
        transferBill.setConfirmUserId(currentUser.getUserId());
        transferBill.setConfirmUserName(currentUser.getUserName());
        //Step2.保存
        transferBillService.saveAndConfirmTransferBill(ListUtil.toList(transferBill));

        return ResultGenerator.genSuccessResult();
    }

    @ApiOperation(value = "查询装箱单")
    @GetMapping("/packwork/select")
    public Result selectPackWorkList(TransferBillCriteria criteria) {
        // 设置单据类型
        criteria.setBillType(InStockConstant.TRANS_TYPE_PACK_BOX);
        // 根据条件查询的装箱单数据
        List<TransferBill> transferBills = transferBillService.selectBillList(criteria);
        // 设置页面的分页条件
        PageHelper.startPage(criteria.getPageNum(), criteria.getPageSize());
        // 封装分页的数据
        PageInfo pageInfo = new PageInfo(transferBills);
        // 返回成功的结果
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @ApiOperation(value = "查询上架单")
    @GetMapping("/putaway/select")
    public Result selectPackingList(TransferBillCriteria criteria) {
        // 设置单据类型
        criteria.setBillType(InStockConstant.TRANS_TYPE_UPPER);
        // 根据条件查询上架单数据
        List<TransferBill> transferBills = transferBillService.selectBillList(criteria);
        // 设置页面的分页条件
        PageHelper.startPage(criteria.getPageNum(), criteria.getPageSize());
        // 封装分页的数据
        PageInfo pageInfo = new PageInfo(transferBills);
        // 返回成功的结果
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @ApiOperation(value = "查询转移单")
    @GetMapping("/transferBill/list")
    public Result selectTransferBill(TransferBillCriteria criteria) {
        // 设置单据类型--4(转移单)
        criteria.setBillType(InStockConstant.TRANS_TYPE_MOVE);
        // 根据条件查询上架单数据
        List<TransferBill> transferBills = transferBillService.selectBillList(criteria);
        // 设置页面的分页条件
        PageHelper.startPage(criteria.getPageNum(), criteria.getPageSize());
        // 封装分页的数据
        PageInfo pageInfo = new PageInfo(transferBills);
        // 返回成功的结果
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @PostMapping("/transferBill/insert")
    @ApiOperation(value = "添加转移单", notes = "添加转移单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "access-token", value = "token", paramType = "header", dataType = "String", dataTypeClass = String.class, required = true)
    })
    public Result addTransferBill(@RequestBody TransferBillCriteria criteria, @ApiIgnore @User CurrentUser currentUser) {
        if (currentUser == null) {
            // 没有登录
            return ResultGenerator.genFailResult(CommonCode.MISSING_PERMISSION_PARAMTER, null);
        }
        List<TransferBill> transferBills = new ArrayList<>();
        TransferBill transferBill = new TransferBill();
        //仓库
        transferBill.setWareId(criteria.getWareId());
        //转移单类型
        transferBill.setBillType(InStockConstant.TRANS_TYPE_MOVE);
        //来源库位 收货区库位
        Inventory boxIvt = inventoryService.getOneByField("box_code", criteria.getFromBoxCode());
        if (ObjectUtil.isNull(boxIvt)) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "根据容器号：" + criteria.getFromBoxCode() + "未找到对应的库存");
        }
        //FIXME: 这里写死，冻结的物料不能转移
        if (InventoryConstant.TRANSACT_STATE_UNNORMAL.equals(boxIvt.getState())) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "容器内物料未质检，禁止上架!");
        }
        transferBill.setFromCellCode(boxIvt.getCellCode());
        //目标库位
        transferBill.setToCellCode(criteria.getToCellCode());
        //来源容器
        transferBill.setFromBoxCode(criteria.getFromBoxCode());
        transferBill.setItemCode(boxIvt.getItemCode());
        transferBill.setBatchName(boxIvt.getBatchName());
        transferBill.setPackDetailId(boxIvt.getPackDetailId());
        transferBill.setQty(new BigDecimal(boxIvt.getQuantity()));
        //标记冻结解冻标识
        if (boxIvt.getFreezeQuantity() > 0) {
            //说明是待检的物料
            transferBill.setFreezeFlag(AsnManageConstant.ACCEPT_QC_STATE_TODO);
        }
        //确认人
        transferBill.setConfirmUserId(currentUser.getUserId());
        transferBill.setConfirmUserName(currentUser.getUserName());
        transferBill.setConfirmTime(DateUtil.now());
        transferBills.add(transferBill);
        //Step2.保存
        transferBillService.createTransferBill(transferBills);
        return ResultGenerator.genSuccessResult();
    }

    @PostMapping("/PackWork/insert")
    @ApiOperation(value = "添加装箱单", notes = "添加装箱单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "access-token", value = "token", paramType = "header", dataType = "String", dataTypeClass = String.class, required = true)
    })
    public Result addPackWork(@RequestBody TransferBillCriteria criteria, @ApiIgnore @User CurrentUser currentUser) {
        if (currentUser == null) {
            // 没有登录
            return ResultGenerator.genFailResult(CommonCode.MISSING_PERMISSION_PARAMTER, null);
        }
        // 数据复制
        TransferBill transferBill = new TransferBill();
        // 装箱的数据来源库位和目标库位一样
        BeanUtils.copyProperties(criteria, transferBill);
        transferBill.setToCellCode(criteria.getFromCellCode());
        // 设置操作人员编号
        transferBill.setConfirmUserId(currentUser.getUserId());
        transferBill.setConfirmUserName(currentUser.getUserName());
        transferBill.setConfirmTime(DateUtil.now());
        // 设置转移单类型
        transferBill.setBillType(InStockConstant.TRANS_TYPE_PACK_BOX);
        // 准备数据
        List<TransferBill> transferBills = new ArrayList<>();
        transferBills.add(transferBill);
        // 执行保存的方法 saveAndConfirmTransferBill 保存会直接确认不使用这个方法
        transferBillService.createTransferBill(transferBills);
        // 新增成功返回消息
        return ResultGenerator.genSuccessResult();
    }

    @PostMapping("/transferBill/updateState")
    @ApiOperation(value = "转移单确认", notes = "转移单确认")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "access-token", value = "token", paramType = "header", dataType = "String", dataTypeClass = String.class, required = true)
    })
    public Result updateState(@RequestBody TransferBillCriteria criteria, @ApiIgnore @User CurrentUser currentUser) {
        if (currentUser == null) {
            // 没有登录
            return ResultGenerator.genFailResult(CommonCode.MISSING_PERMISSION_PARAMTER, null);
        }
//        // 准备数据
//        criteria.setBillType(InStockConstant.TRANS_TYPE_MOVE);
        List<TransferBill> transferBills = transferBillService.selectBillList(criteria);
        // 执行转移单确认的方法
        transferBillService.confirmTransferBill(transferBills);
        // 新增成功返回消息
        return ResultGenerator.genSuccessResult();
    }

    @ApiOperation(value = "上架推荐库位")
    @GetMapping("/upper/recommend")
    public Result recommendUpperCellForPDA(@RequestParam String boxCode) {
        //Step1.校验容器库存是否是待收货区的
        InventoryCriteria inventoryCriteria = new InventoryCriteria();
        inventoryCriteria.setBoxCode(boxCode);
        List<InventoryDto> list = inventoryService.findList(inventoryCriteria);
        if (list.size() == 0) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "容器：[" + boxCode + "]未查询到库存");
        }
        if (ObjectUtil.notEqual(BaseSystemConstant.CELL_USE_TYPE_ACCEPT.toString(), list.get(0).getCellUseType())) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "容器：[" + boxCode + "]库存在不收货区");
        }
        if (list.size() > 1) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "容器：[" + boxCode + "]存在多条数据");
        }

        //Step2.找到对应的上架策略
        InventoryDto inventoryDto = list.get(0);
        String itemCode = inventoryDto.getItemCode();
        List<UpperTacticDetailDto> upperTacticDetails = itemInfoService.findUpperTacticDetails(itemCode);

        //Step3.根据策略找到满足条件的库位
        List<CellInfoDto> recommendUpperCells = new ArrayList<>();
        for (UpperTacticDetailDto upperTacticDetail : upperTacticDetails) {
            recommendUpperCells = cellInfoService.getRecommendUpperCells(upperTacticDetail);
            //暂时只处理一个
            break;
        }
        for (CellInfoDto recommendUpperCell : recommendUpperCells) {
            Integer boxNum = inventoryService.getBoxNumInCell(recommendUpperCell.getCellCode());
            recommendUpperCell.setBoxNum(boxNum);
        }

        return ResultGenerator.genSuccessResult(recommendUpperCells);
    }


}
